﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace KC.DataAccess.Global
{
	/// <summary>Logs information, usually errors</summary>
	public static class Logging
	{
		/// <summary>How big can a logfile get before truncating it?</summary>
		private const int MaxFilesize = 1048576;
		/// <summary>Logs a message to a file, and removes the top of it if it's too big</summary>
		/// <param name="filename">File to log to</param>
		/// <param name="msg">Message to log</param>
		public async static Task LogFile(string filename, string msg)
		{
			if (string.IsNullOrEmpty(filename)) throw new ArgumentNullException("filename");
			if (string.IsNullOrEmpty(msg)) throw new ArgumentNullException("msg");

			try { 
				Task t = null;
				if (File.Exists(filename))
					t = Task.Run(() => File.AppendAllText(filename, DateTime.Now.ToString("MM/dd/yy HH:mm:ss.fff") + " │ " + msg + "\r\n"));
				else t = Task.Run(() => File.WriteAllText(filename, DateTime.Now.ToString("MM/dd/yy HH:mm:ss.fff") + " │ " + msg + "\r\n"));
				await Task.Run(() => t);
			}
			catch { }
			if (new FileInfo(filename).Length > MaxFilesize)
				try { await Task.Run(() => File.WriteAllText(filename, File.ReadAllText(filename).Substring((int)((Double)MaxFilesize * .75D)))); }
				catch { }
		}
		/// <summary>Logs an error to SQL and/or a file, depending on which is not null.</summary>
		/// <param name="ex">Exception object</param>
		/// <param name="ConnStr">Connection string</param>
		/// <param name="filename">Logfile</param>
		public async static Task LogError(Exception ex, string ConnStr = null, string filename = null)
		{
			if (string.IsNullOrEmpty(filename) && string.IsNullOrEmpty(ConnStr)) throw new ArgumentNullException("Enter either filename or Connection String");
			if (filename != null) await LogFile(filename, ex.ToString());
			if (ConnStr != null) await LogSql(ConnStr, ex);
		}
		/// <summary>Logs an error to SQL and/or a file, depending on which is not null.</summary>
		/// <param name="ex">Exception object</param>
		/// <param name="ConnStr">Connection string</param>
		/// <param name="filename">Logfile</param>
		public async static Task LogError(Exception ex, string ConnStr, string msg, string details)
		{
			if (string.IsNullOrEmpty(ConnStr)) throw new ArgumentNullException("Enter either filename or Connection String");
			await LogSql(ConnStr, ex);
		}
		/// <summary>Logs a message to SQL</summary>
		/// <param name="ConnStr">SQL Connection String</param>
		/// <param name="msg">Message to log</param>
		private async static Task LogError(string ConnStr, string msg, string details = null)
		{
			if (string.IsNullOrEmpty(ConnStr)) throw new ArgumentNullException("ConnStr");
			if (string.IsNullOrEmpty(msg)) throw new ArgumentNullException("msg");

			await SQL.ExecuteNonQuery(ConnStr, "insert into errors (datetime, message, details, stacktrace) values (getdate(), '" +
				msg.Replace("'", "''") + "', " + (string.IsNullOrEmpty(details) ? "null" : ("'" + details.Replace("'", "''") + "'")) + ", '" + Environment.StackTrace.Replace("'", "''") + ")");
		}
		/// <summary>Logs a message to SQL</summary>
		/// <param name="ConnStr">SQL Connection String</param>
		/// <param name="ex">Exception object</param>
		/// <param name="details">Details of the error</param>
		/// <param name="msg">Message to log</param>
		private async static Task LogSql(string ConnStr, Exception ex, string msg = null, string details = null)
		{
			if (string.IsNullOrEmpty(ConnStr)) throw new ArgumentNullException("ConnStr");
			if (string.IsNullOrEmpty(msg)) throw new ArgumentNullException("msg");
			if (ex == null) throw new ArgumentNullException("ex");

			await SQL.ExecuteNonQuery(ConnStr, "insert into errors (datetime, ex, message, details, stacktrace) values (getdate(), '" +
				ex.ToString().Replace("'", "''") + "', " +
				(string.IsNullOrEmpty(msg) ? "null" : ("'" + msg.Replace("'", "''") + "'")) + ", " +
				(string.IsNullOrEmpty(details) ? "null" : ("'" + details.Replace("'", "''") + "'")) + ", '" +
				Environment.StackTrace.Replace("'", "''") + ")");
		}
	}
}
